package io.netty.example.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;

/**
 * Netty服务端
 */
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        // 1.创建bossGroup线程组: 处理网络事件--连接事件 线程数默认为: 2 * 处理器线程数
        // new DefaultThreadFactory("boos") 指定 eventLoopGroup名称
        EventLoopGroup bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("boos"));
        // 2.创建workerGroup线程组: 处理网络事件--读写事件 2 * 处理器线程数
        EventLoopGroup workerGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("work"));
        try {
            // 3.创建服务端启动助手
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 4.设置bossGroup线程组和workerGroup线程组
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)// 5.设置服务端通道实现
                    .option(NioChannelOption.SO_BACKLOG, 1024)// 6.参数设置-设置线程队列中等待连接个数
                    .childOption(NioChannelOption.TCP_NODELAY, true)// 该选项是需要等到发送的数据量最大的时候，一次性发送数据，适用于文件传输
                    .childOption(NioChannelOption.SO_KEEPALIVE, Boolean.TRUE)// 6.参数设置-设置活跃状态,child是设置workerGroup 该参数用于设置TCP连接，当设置该选项以后，连接会测试链接的状态，这个选项用于可能长时间没有数据交流的连接。当设置该选项以后，如果在两小时内没有数据的通信时，TCP会自动发送一个活动探测数据报文
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {//7.创建一个通道初始化对象
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // name 对handler加名称
                            ch.pipeline().addLast("NettyServerOutHandle", new NettyServerOutHandle());
                            //8.向pipeline中添加自定义业务处理handler
                            ch.pipeline().addLast("NettyServerHandle", new NettyServerHandle());

                            ch.pipeline().addLast("logging", new LoggingHandler(LogLevel.INFO));
                        }
                    });
            // 9.启动服务端并绑定端口,同时将异步改为同步
            ChannelFuture future = bootstrap.bind(9999);
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        System.out.println("端口绑定成功!");
                    } else {
                        System.out.println("端口绑定失败!");
                    }

                }
            });
            System.out.println("服务器启动成功....");
            // 10.关闭通道(并不是真正意义上的关闭,而是监听通道关闭状态)和关闭连接池
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
